#pragma once
#include <iostream>
#include <memory>
#include <unistd.h>
#include "Socket.hpp"
using namespace SocketModule;
using namespace LogModule;
class SelectServer

{
  const static int size = sizeof(fd_set) * 8;
  const static int defaultfd = -1;

public:
  SelectServer(int port)
      : _listensock(std::make_unique<TcpSocket>()),
        _isrunning(true)
  {
    _listensock->BuildTcpSocketMetond(port);
    for (int i = 0; i < size; i++)
    {
      _fd_array[i] = defaultfd;
    }
    _fd_array[0] = _listensock->Fd();
  }
  void Start()
  {
    _isrunning = true;
    while (_isrunning)
    {
      fd_set rfds;
      FD_ZERO(&rfds);
      int maxfd = defaultfd;
      for (int i = 0; i < size; i++)
      {
        if (_fd_array[i] == defaultfd)
          continue;
        FD_SET(_fd_array[i], &rfds);
        if (maxfd < _fd_array[i])
          maxfd = _fd_array[i];
      }
      Printfd();
      int n = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);

      switch (n)
      {
      case -1:
        LOG(LogLevel::ERROR) << "select error";
        break;
      case 0:
        LOG(LogLevel::INFO) << "time out ";
        break;
      default:
        LOG(LogLevel::DEBUG) << "已有事件就绪。。。。。，n: " << n;
        Dispatcher(rfds);
        break;
      }
    }
    _isrunning = false;
  }
  void Dispatcher(fd_set &rfds)
  {
    for (int i = 0; i < size; i++)
    {
      if (_fd_array[i] == defaultfd)
        continue;
      if (FD_ISSET(_fd_array[i], &rfds))
      {
        if (_fd_array[i] == _listensock->Fd())
        {
          Accepter();
        }
        else
        {
          Recver(_fd_array[i], i);
        }
      }
    }
  }
  void Accepter()
  {
    InetAddr client;
    int sockfd = _listensock->Accept(&client);
    if (sockfd >= 0)
    {
      int pos = 0;
      for (; pos < size; pos++)
      {
        if (_fd_array[pos] == defaultfd)
          break;
      }
      if (pos == size)
      {
        LOG(LogLevel::INFO) << "select server full";
        close(sockfd);
      }
      else
      {
        _fd_array[pos] = sockfd;
      }
    }
  }
  void Recver(int fd, int pos)
  {
    char buffer[1024];
    ssize_t n = recv(fd, buffer, sizeof(buffer) - 1, 0);
    if (n > 0)
    {
      buffer[n] = 0;
      std::cout << "client say@ " << buffer << std::endl;
    }
    else if (n == 0)
    {
      LOG(LogLevel::INFO) << "client quit...";
      _fd_array[pos] = defaultfd;
      close(fd);
    }
    else
    {
      LOG(LogLevel::ERROR) << "recv error";
      _fd_array[pos] = defaultfd;
      close(fd);
    }
  }
  void Printfd()
  {
    std::cout << "_fd_array[]: ";
    for (int i = 0; i < size; i++)
    {
      if (_fd_array[i] == defaultfd)
        continue;
      std::cout << _fd_array[i] << " ";
    }
    std::cout << "\r\n";
  }
  void Stop()
  {
    _isrunning = true;
  }
  ~SelectServer() = default;

private:
  std::unique_ptr<Socket> _listensock;
  bool _isrunning;

  int _fd_array[size];
};